package net.qiqbframework.persisthanding;

import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.common.Registration;
import net.qiqbframework.messaging.*;
import net.qiqbframework.messaging.task.DefaultMessageTask;
import net.qiqbframework.messaging.task.MessageTask;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
public class AggregatePersistBusImpl implements AggregatePersistBus {

    private final ConcurrentMap<String, List<MessageHandler<? super PersistMessage<?>>>> subscriptions = new ConcurrentHashMap<>();
    private final List<MessageHandlerInterceptor<? super PersistMessage<?>>> handlerInterceptors = new CopyOnWriteArrayList<>();


    protected AggregatePersistBusImpl(AggregatePersistBusBuilder builder) {
        builder.validate();
    }


    @Override
    public void save(@Nonnull PersistMessage<?> message) throws Exception {

        final List<MessageHandler<? super PersistMessage<?>>> persistMessageHandlers = findLoadHandler(message.getPersistName());
        if (!persistMessageHandlers.isEmpty()) {
            for (MessageHandler<? super PersistMessage<?>> messageHandler : persistMessageHandlers) {
                MessageTask<PersistMessage<?>> persistMessageMessageTask = DefaultMessageTask.startAndGet(message);
                InterceptorChain chain = new DefaultInterceptorChain<>(persistMessageMessageTask, handlerInterceptors, messageHandler);
                try {
                    final ResultMessage<Object> persistResult = persistMessageMessageTask.executeWithResult(chain::proceed, throwable -> true);
                    if (persistResult.isExceptional()) {
                        throw new RuntimeException(persistResult.exceptionResult());
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }

    public List<MessageHandler<? super PersistMessage<?>>> findLoadHandler(@Nonnull String businessIdName) {
        List<MessageHandler<? super PersistMessage<?>>> handlers = new ArrayList<>();
        final List<MessageHandler<? super PersistMessage<?>>> matched = subscriptions.get(businessIdName);
        if (matched != null) {
            handlers.addAll(matched);
        }

        final List<MessageHandler<? super PersistMessage<?>>> commonHandlers = subscriptions.get("*");
        if (commonHandlers != null) {
            handlers.addAll(commonHandlers);
        }
        return handlers;
    }

    @Override
    public Registration subscribe(@Nonnull String aggregateNaming, @Nonnull MessageHandler<? super PersistMessage<?>> handler) {
        subscriptions.putIfAbsent(aggregateNaming, new ArrayList<>());
        final List<MessageHandler<? super PersistMessage<?>>> messageHandlers = subscriptions.get(aggregateNaming);
        messageHandlers.add(handler);
        return () -> messageHandlers.remove(handler);
    }


}
